classdef DisplayWidget < handle
    
%
%     CISNE is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     any later version.
%
%     CISNE is distributed in the hope that it will be useful,
%     but WITHOUT ANY WARRANTY; without even the implied warranty of
%     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%     GNU General Public License for more details.
%
%     You should have received a copy of the GNU General Public License
%     along with CISNE.  If not, see <http://www.gnu.org/licenses/>.

% Copyright 2011. Jose Maria Garcia-Valdecasas Bernal
    
    properties (SetAccess=private)
        m_inputGrids=[]; % structure with all Input Grids
        m_compGrids=[]; %structure with all computational grids
        m_controlPoints=[];%structure with all control points
        m_inputAx=[]; %handle for input grids' axes
        m_compAx=[]; %handle for computational grids' axes
        m_action=[]; %new/edit/select grid action. (maybe not needed here)
        m_axProp=[]; %axes properties.
        m_axLimits=[]; %axes limits.
        m_Figure=[]; %Parent Figure, needed to retrieve handles.
        m_activeGrid=[]; %name of current grid
        m_activeElement=[];
        m_tempRect=[]; %temporary line used to draw rectangles.
        m_tempPoint=[];%temporary line used to move control points.
        m_pSize=[]; %only used to know parent size... useful?
        m_cMainProp=[]; %properties for comput. main grids
        m_cNestProp=[]; %properties for comput. nested grids
        m_PointsProp=[]; %properties for control points
        m_iGridsProp=[]; %properties for input grids.
    end
    
    methods
        function obj=DisplayWidget(parent)
            %constructor function
            handles=guidata(parent);
            obj.m_Figure=handles.figure1;
            clear handles; %remove from memory.
            
            %initialize settings
            obj.initSettings();            
            
            %draw axes
            obj.initAxes(parent);
            
        end
        
        %basic funtions go here
        
        initAxes(obj,parent);
                
        initSettings(obj);
        defaultSettings(obj);
        
        addInputGrid(obj,name,file);
		loadInputGrid(obj,name,file);
        
        function delInputGrid(obj,name)
            if isfield(obj.m_inputGrids,name)
                if ishandle(obj.inputGrids.(name).handle)
                    delete(obj.inputGrids.(name).handle);                    
                end
                obj.m_inputGrids=rmfield(obj.m_inputGrids,name);
            end
        end 
        
        
        refreshDisplay(obj);
        
        function grList=getInputGridList(obj)
            if ~isempty(obj.m_inputGrids)
                grList=fieldnames(obj.m_inputGrids);
            else
                grList=[];
            end
        end
        
        function prop=getAxProp(obj,name)
            prop=obj.m_axProp.(name);
        end
        
        function setAxProp(obj,name,value)
            obj.m_axProp.(name)=value;
        end
        
        function value=getCGridColor(obj,type,color)
            grid=['m_' type 'Prop'];
            value=obj.(grid).(color);
        end
        
        function setCGridColor(obj,type,color,value)
            grid=['m_' type 'Prop'];
            obj.(grid).(color)=value;
        end
        
        function setGridColormap(obj,grid,map,c1,c2)
            obj.m_iGridsProp.(grid).(map).c1=c1;
            obj.m_iGridsProp.(grid).(map).c2=c2;
        end
        
        function [c1,c2]=getGridColormap(obj,grid,map)
            c1=obj.m_iGridsProp.(grid).(map).c1;
            c2=obj.m_iGridsProp.(grid).(map).c2;
        end
        
        function value=getCPointProp(obj,prop)
            value=obj.m_PointsProp.(prop);
        end
        
        function setCPointProp(obj,prop,value)
            obj.m_PointsProp.(prop)=value;
        end
        
        function setMethod(obj,grid,method)
            obj.m_inputGrids.(grid).method=method;
        end
        
        function method=getMethod(obj,grid)
            method=obj.m_inputGrids.(grid).method;
        end
        
        function data=getData(obj,grid)
            if ~isfield(obj.m_inputGrids.(grid),'data')
                data=[];
            else
                data=obj.m_inputGrids.(grid).data;
            end
        end
        
        function setData(obj,grid,data)
            obj.m_inputGrids.(grid).data=data;
        end
        
        function h=getHandle(obj,grid)
            if ~isfield(obj.m_inputGrids.(grid),'handle')
                h=[];
            else
                h=obj.m_inputGrids.(grid).handle;
            end
        end
        
        function setAction(obj,action)
            %remembers which kind of action wants the user
            %(edit/select/zoom)
            obj.m_action=action;
			if strcmp(action,'edit')
                if obj.isCGrid(obj.m_activeElement)
                    obj.showGridCorners();
                elseif obj.isCPoint(obj.m_activeElement)
                    obj.activateCPoint();
                end
			end
        end
		
        function activateCPoint(obj)
            item=obj.m_activeElement();
            %flip colors
            face=get(obj.m_controlPoints.(item),'MarkerEdgeColor');
            edge=get(obj.m_controlPoints.(item),'MarkerFaceColor');
            
            set(obj.m_controlPoints.(item),'MarkerFaceColor',face,...
                'MarkerEdgeColor',edge);
        end
        
        function deactivateCPoint(obj)
            item=obj.m_activeElement();
            set(obj.m_controlPoints.(item),obj.m_PointsProp);
        end
        
		function showGridCorners(obj)
			grid=obj.m_activeGrid;
			items=obj.getPointObjs(grid);
            fields=sort(fieldnames(items));
            
            for k=1:length(fields)
                set(items.(fields{k}),'Visible','on');
            end
			
		end
		
		function hideGridCorners(obj)
			grid=obj.m_activeGrid;
			items=obj.getPointObjs(grid);
            fields=sort(fieldnames(items));
            
            for k=1:length(fields)
                set(items.(fields{k}),'Visible','off');
            end
			
		end
        
        function bool=isAction(obj,action)
            %check if action is current saved action.
            bool=strcmp(obj.m_action,action);
        end
        
        function grid=activeGrid(obj)
            %retrieve which grid is the active one to interact with it
            grid=obj.m_activeGrid;
        end
        
        function setActiveGrid(obj,grid)
            %sets active grid
            obj.m_activeGrid=grid;
            
        end
        
        function setActiveElement(obj,tag)
            obj.m_activeElement=tag;
            if obj.isCGrid(tag)
                obj.setActiveGrid(tag);
            end
        end
        
        function bool=isActiveElement(obj,tag)
            bool=strcmp(obj.m_activeElement,tag);
        end
        
        function resetTempRect(obj)
            %resets temporary rectangle used to draw selections.
            if ishandle(obj.m_tempRect)
                delete(obj.m_tempRect);
            end
            obj.m_tempRect=line('Parent',obj.m_compAx,'Xdata',[],...
                'Ydata',[],'Color',[0.4 0.4 0.4],'LineStyle','--');
        end
        
        function setTempRect(obj,XData,YData)
            %draws temporary rectangle
            set(obj.m_tempRect,'Xdata',XData,'YData',YData);
        end
        
        function [X,Y]=getTempRect(obj)
            %gets corners of temporary rectangle
            X=get(obj.m_tempRect,'Xdata');
            Y=get(obj.m_tempRect,'Ydata');
        end
        
        function resetTempPoint(obj)
            %resets temp point used to move control points.
            if ishandle(obj.m_tempPoint)
                delete(obj.m_tempPoint);
            end
            obj.m_tempPoint=line('Parent',obj.m_compAx,'Xdata',[],...
                'Ydata',[],'MarkerFaceColor',[0.4 0.4 0.4],...
                'MarkerEdgeColor',[0.4 0.4 0.4]);
        end
        
        function setTempPoint(obj,XData,YData)
            %draws temp control point.
            set(obj.m_tempRect,'Xdata',XData,'YData',YData);
        end
        
        function p=currentPoint(obj)
            %gets coordinates of pointer position using computational grid
            %as reference coordinates.
            p=get(obj.m_compAx,'CurrentPoint');
            p=p(1,:);
        end
        
        function [xlim ylim]=getAxisLim(obj)
            %retrieves limits of input grid axis (same as comp grid)
            xlim=get(obj.m_inputAx,'XLim');
            ylim=get(obj.m_inputAx,'YLim');
        end
        
        function bool=isCGrid(obj,tag)
            %returns true if tag is a valid computational grid
            bool=isfield(obj.m_compGrids,tag);
            
        end
        
        function bool=isCPoint(obj,tag)
            %returns true if tag is a valid computational grid
            bool=isfield(obj.m_controlPoints,tag);
            
        end
        
        function points=getPointObjs(obj,tag)
            %get the objects of the corners for that tagname
            points=obj.m_compGrids.(tag).points;
        end
        
        function points=getPointCoord(obj,tag)
            if nargin==1
                tag=obj.m_activeGrid;
            end
            items=obj.getPointObjs(tag);
            fields=sort(fieldnames(items));
            points=zeros(2,length(fields));
            for k=1:length(fields)
                x=get(items.(fields{k}),'Xdata');
                y=get(items.(fields{k}),'Ydata');
                points(:,k)=[x;y];
            end
        end
        
        function pos=getWidgetPosition(obj)
            pos=obj.m_pSize;
        end
        
        
        function drawCGrid(obj,grid,x,y)
            set(obj.m_compGrids.(grid).rect,'Xdata',x,'Ydata',y);
            items=obj.getPointObjs(grid);
            fields=sort(fieldnames(items));
            
            for k=1:length(fields)
                set(items.(fields{k}),'Xdata',x(k));
                set(items.(fields{k}),'Ydata',y(k));
            end
        end
        
        function drawCPoint(obj,grid,x,y)
            set(obj.m_controlPoints.(grid),'Xdata',x,'Ydata',y);
        end
        
        drawIGrid(obj,grid);
        
        function addCompGrid(obj,name)
            
            if strfind(name,'cMain')
                obj.m_compGrids.(name).rect=line('Parent',obj.m_compAx,...
                    'Xdata',[],'Ydata',[],'Color',...
                    obj.m_cMainProp.MarkerEdgeColor,'Tag',name);
                props=obj.m_cMainProp;
            else
                obj.m_compGrids.(name).rect=line('Parent',obj.m_compAx,...
                    'Xdata',[],'Ydata',[],'Color',...
                    obj.m_cNestProp.MarkerEdgeColor,'Tag',name);
                props=obj.m_cNestProp;
            end
            
            %create extra lines for corners.
            obj.m_compGrids.(name).points.P0=line('Parent',obj.m_compAx,...
                'Xdata',[],'Ydata',[],props,'Tag',[name '-Corners'],'Visible','off');
            obj.m_compGrids.(name).points.P1=line('Parent',obj.m_compAx,...
                'Xdata',[],'Ydata',[],props,'Tag',[name '-Corners'],'Visible','off');
            obj.m_compGrids.(name).points.P2=line('Parent',obj.m_compAx,...
                'Xdata',[],'Ydata',[],props,'Tag',[name '-Corners'],'Visible','off');
            obj.m_compGrids.(name).points.P3=line('Parent',obj.m_compAx,...
                'Xdata',[],'Ydata',[],props,'Tag',[name '-Corners'],'Visible','off');
        end
        
        loadCompGrid(obj,name);
        
        function delCompGrid(obj,name)
            if isfield(obj.m_compGrids,name)
                if ishandle(obj.m_compGrids.(name).rect)
                    delete(obj.m_compGrids.(name).rect);
                end
                if ishandle(obj.m_compGrids.(name).points.P0)
                    delete(obj.m_compGrids.(name).points.P0);
                end
                if ishandle(obj.m_compGrids.(name).points.P1)
                    delete(obj.m_compGrids.(name).points.P1);
                end
                if ishandle(obj.m_compGrids.(name).points.P2)
                    delete(obj.m_compGrids.(name).points.P2);
                end
                if ishandle(obj.m_compGrids.(name).points.P3)
                    delete(obj.m_compGrids.(name).points.P3);
                end
                obj.m_compGrids=rmfield(obj.m_compGrids,name);
            end
        end
        
        
        
        function addCPoint(obj,name)
            obj.m_controlPoints.(name)=line('Parent',obj.m_compAx,...
                    'Xdata',[],'Ydata',[],obj.m_PointsProp,'Tag',name);
            
        end
        
        function delCPoint(obj,name)
            if isfield(obj.m_controlPoints,name)
                if ishandle(obj.m_controlPoints.(name))
                    delete(obj.m_controlPoints.(name));                    
                end
                obj.m_controlPoints=rmfield(obj.m_controlPoints,name);
            end
        end
        
        
        %sets axes properties (obtained by config dialog)
        setAxesProp(obj,varargin);
        
        %redraw axes with properties (AKA insert m_axProp data into axes)
        function refreshAxes(obj)
            set(obj.m_inputAx,obj.m_axProp);
            
        end
        
        
        %get axes properties (for any purpose)
        function Props=getAxesProp(obj)
            Props=obj.m_axProp;
        end
               
        
        function setAxesLimits(obj,xmin,xmax,ymin,ymax)
            obj.m_axLimits=[xmin xmax ymin ymax];
            obj.zoomExtent();
            %update limits for input and computational axes and refresh.
        end
        
        function lim=getAxesLimits(obj)
            lim=obj.m_axLimits;
        end
        
        zoomIn(obj);
        zoomOut(obj);
        function zoomArea(obj,x,y)
            set(obj.m_inputAx,'XLim',x,'YLim',y);
            set(obj.m_compAx,'XLim',x,'YLim',y);
            obj.setAction('');
            
        end
        function zoomExtent(obj)
            l=obj.getAxesLimits;
            set(obj.m_inputAx,'XLim',[l(1) l(2)],'YLim',[l(3) l(4)]);
            set(obj.m_compAx,'XLim',[l(1) l(2)],'YLim',[l(3) l(4)]);
        end
        
        function trickSWANPath(obj,path)
            %should not go here... but it's a quick trick :)
            handles=guidata(obj.m_Figure);
            handles.SWANPath=path;
            guidata(obj.m_Figure,handles);
        end
		
		function resetDisplay(obj)
			obj.m_inputGrids=[]; 
			obj.m_compGrids=[]; 
			obj.m_controlPoints=[];
			cla(obj.m_inputAx);
			cla(obj.m_compAx);
			obj.setAxesLimits(0,1,0,1);
		end
    end
         
    methods(Static)
        [grad,im]=getGradient(c1,c2,numcol);
    end
end

